package com.star.spring.ratelimit.aspect;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;

import com.star.spring.ratelimit.model.AccessLog;
import com.star.spring.ratelimit.service.AccessLogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * 访问日志切面
 *
 * @author star
 * @since 2025-01-24
 */
@Slf4j
@Aspect
@Component
@Order(1) // 最先执行，最后结束
public class AccessLogAspect {

    @Autowired
    private AccessLogService accessLogService;

    @Autowired
    private ObjectMapper objectMapper;

    @Around("execution(* com.star.spring.ratelimit.controller..*(..))")
    public Object logAccess(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        AccessLog accessLog = new AccessLog();

        try {
            // 获取请求信息
            ServletRequestAttributes attributes =
                    (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                return joinPoint.proceed();
            }

            HttpServletRequest request = attributes.getRequest();

            // 记录请求信息
            recordRequestInfo(accessLog, request, joinPoint);

            // 执行目标方法
            Object result = joinPoint.proceed();

            // 记录响应信息
            recordResponseInfo(accessLog, result, startTime);

            // 记录访问日志
            accessLogService.logAccess(accessLog);

            return result;

        } catch (Exception e) {
            // 记录异常信息
            recordExceptionInfo(accessLog, e, startTime);
            accessLogService.logAccess(accessLog);
            accessLogService.logException(accessLog.getRequestId(), accessLog.getMethod(), accessLog.getUri(), e);
            throw e;
        }
    }

    /**
     * 记录请求信息
     */
    private void recordRequestInfo(AccessLog accessLog, HttpServletRequest request, ProceedingJoinPoint joinPoint) {
        try {
            // 基本信息
            accessLog.setMethod(request.getMethod());
            accessLog.setUri(request.getRequestURI());
            accessLog.setUrl(request.getRequestURL().toString());

            // IP信息
            accessLog.setClientIp(getClientIp(request));
            accessLog.setRealIp(getRealIp(request));

            // 用户代理信息
            accessLog.setUserAgent(request.getHeader("User-Agent"));

            // 会话信息
            HttpSession session = request.getSession(false);
            if (session != null) {
                accessLog.setSessionId(session.getId());
            }

            // 请求头信息
            Map<String, String> headers = new HashMap<>();
            Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {
                String headerName = headerNames.nextElement();
                headers.put(headerName, request.getHeader(headerName));
            }
            accessLog.setHeaders(headers);

            // 请求参数
            Map<String, Object> requestParams = new HashMap<>();
            Enumeration<String> parameterNames = request.getParameterNames();
            while (parameterNames.hasMoreElements()) {
                String paramName = parameterNames.nextElement();
                String[] paramValues = request.getParameterValues(paramName);
                if (paramValues.length == 1) {
                    requestParams.put(paramName, paramValues[0]);
                } else {
                    requestParams.put(paramName, paramValues);
                }
            }
            accessLog.setRequestParams(requestParams);

            // 请求体（对于POST请求）
            if ("POST".equalsIgnoreCase(request.getMethod()) || "PUT".equalsIgnoreCase(request.getMethod())) {
                try {
                    Object[] args = joinPoint.getArgs();
                    if (args.length > 0) {
                        accessLog.setRequestBody(args[0]);
                    }
                } catch (Exception e) {
                    log.warn("Failed to get request body", e);
                }
            }

        } catch (Exception e) {
            log.warn("Failed to record request info", e);
        }
    }

    /**
     * 记录响应信息
     */
    private void recordResponseInfo(AccessLog accessLog, Object result, long startTime) {
        try {
            accessLog.setResponseStatus(200); // 默认成功状态
            accessLog.setResponseData(result);
            accessLog.setResponseTime(System.currentTimeMillis() - startTime);
        } catch (Exception e) {
            log.warn("Failed to record response info", e);
        }
    }

    /**
     * 记录异常信息
     */
    private void recordExceptionInfo(AccessLog accessLog, Exception e, long startTime) {
        try {
            accessLog.setResponseStatus(500);
            accessLog.setException(e.getMessage());
            accessLog.setResponseTime(System.currentTimeMillis() - startTime);
        } catch (Exception ex) {
            log.warn("Failed to record exception info", ex);
        }
    }

    /**
     * 获取客户端IP
     */
    private String getClientIp(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }

        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }

        return request.getRemoteAddr();
    }

    /**
     * 获取真实IP（经过代理）
     */
    private String getRealIp(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor;
        }

        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }

        return request.getRemoteAddr();
    }
}
